/*
* 津彩插件beta 1.1.2
* date 20210310
* create by 刘百浲
* QQ:50494558
* */
/***************************图色系列***************************/
function getHexFromInt(argb){
    return ((argb)>>>0).toString(16).slice(-6);
}
function getRbgFromHex(hex) {
    return [
        parseInt(hex.substr(0,2),16),
        parseInt(hex.substr(2,2),16),
        parseInt(hex.substr(4,2),16)
    ]
}
function getRgbFromInt(argb){
    let rgb = [];
    rgb[0] = (argb & 0xff0000) >> 16;
    rgb[1] = (argb & 0xff00) >> 8;
    rgb[2] = (argb & 0xff);
    return [rgb[0],rgb[1],rgb[2]];
}
function getIntFromHex(color){
    let data=[];
    data[0]=parseInt(color.substr(0,2),16);
    data[1]=parseInt(color.substr(2,2),16);
    data[2]=parseInt(color.substr(4,2),16);
    return getIntFromColor(data[0],data[1],data[2])
}
function getIntFromColor(r,g,b){
    return ((0xFF << 24)|(r << 16)|(g << 8)|b);
}
function getHexFromColor(r,g,b) {
    return getHexFromInt(((0xFF << 24)|(r << 16)|(g << 8)|b))
}
/**
 *ret = cmpColorEx(481|138|0x24A060-0x101010,214|124|0x24A060-0x101010,408|280|0xEEEEEE-0x101010,553|359|0xFFFFFF-0x101010,553|444|0xFFFFFF-0x101010, "0.95");
 * @param str 多点比色
 * */
function parseColor(str) {
    let ret=[];
    str=str.replace(/0x/g,'');
    str=str.replace(/0x/g,'');
    let data = str.split(',');
    let res=[];
    let temp;
    for(let v in data){
        res=data[v].split('|');
        if(res[2].indexOf('-')!==-1){
            temp = res[2].split('-');
            ret.push([parseInt(res[0]),parseInt(res[1]),getIntFromHex(temp[0]),temp[1]])
        }else {
            ret.push([parseInt(res[0]),parseInt(res[1]),getIntFromHex(res[2]),''])
        }
    }
    return ret
}
/**
 * @description 多点比色点击
 * <Br/>other int大于1正整数:超时时间毫秒
 * <Br/>int负整数:找到(点击)后延时
 * <Br/>int 0-1小米:查找的精度
 * <Br/>string:debug会执行调试所有的点,其它的string是点击后执行logi()
 * <Br/>传入数组:则点击数组的坐标例如[100,88]
 * <Br/>布尔值true需要点击,false不点击
 * <Br/>所有参数不区分顺序
 * @return boolean|布尔型
 * @param str 默认是text搜索
 * */
function cmpColorEx(str) {
    let sim=0.9,debug=false,click=false,tb,delay=0,waiting=0,say='';
    if(!str){
        return false
    }
    if(typeof (str)!=='string'){
        return false
    }
    let data=parseColor(str),color;
    tb=[data[0][0],data[0][1]];
    //处理可变参数
    if(arguments.length>=1){
        for (let i = 1; i < arguments.length; i++) {
            switch (typeof (arguments[i])) {
                case "boolean":
                    click=arguments[i]?true:click;
                    break;
                case "number":
                    if(arguments[i]<1){
                        waiting=Math.abs(arguments[i]);
                    }else if (arguments[i]>0&&arguments[i]<=1) {
                        sim=arguments[i];
                    }else {
                        delay=arguments[i];
                    }
                    break;
                case "object":
                    //传入点击的xy后,click强制为true
                    tb=[arguments[i][0],arguments[i][1]];
                    click=true;
                    break;
                case "string":
                    if(arguments[i]==='debug'){
                        debug=true
                    }else {
                        //输出到日志文件
                        say=arguments[i];
                    }
                    break;
                default:
                    //参数错误
                    break
            }
        }
    }
    if(debug){
        let bitmap = JcScreen();
        for(let i in data){
            color=image.pixel(bitmap,data[i][0],data[i][1]);
            if(colorSim(color,data[i][2],sim,data[i][3])){
                logi('第'+i+'个找到了,填入颜色为:'+getHexFromInt(data[i][2])+'|实际颜色为:'+getHexFromInt(color))
            }else {
                logw('第'+i+'个未找到,填入颜色为:'+getHexFromInt(data[i][2])+'|实际颜色为:'+getHexFromInt(color))
            }
        }
        image.recycle(bitmap);
        return false
    }
    let times=time()+waiting/1000;
    do {
        let result = image.cmpColorEx(str,sim,0,0,0,0);
        if(result){
            if(click){
                clickPoint(tb[0],tb[1])
            }
            if(say){
                //输出到日志文件
                logi(say)
            }
            if(delay>0){
                sleep(delay)
            }
            return true
        }else if(waiting>0){
            //继续等待
            sleep(350);
        }
    }while (times>time());
    return false
}
/**
 * @description 多点或者多点数组比色，找到所有符合标准的点，依次查找，如果找到就返回当前points的索引值，如果返回-1，说明都没有找到
 * 运行环境: 无限制
 * <Br/>
 * 可变参数
 * @param str 多组多点比色
 */
function cmpColorExArray(str){
    let t=new Date().getTime();
    if(typeof (str)!=='object'){
        return -1
    }
    let sim=0.85,click=false,tb,delay=0,waiting=0,say='';
    let find = -1;
    if(!str){
        return find;
    }
    //处理可变参数
    if(arguments.length>=1){
        for (let i = 1; i < arguments.length; i++) {
            switch (typeof (arguments[i])) {
                case "boolean":
                    click=arguments[i];
                    break;
                case "number":
                    if(arguments[i]>1){
                        delay=arguments[i];
                    }else if (arguments[i]>0&&arguments[i]<=1) {
                        sim=arguments[i];
                    }else {
                        waiting=Math.abs(arguments[i]);
                    }
                    break;
                case "object":
                    //传入点击的xy后,click强制为true
                    tb=[arguments[i][0],arguments[i][1]];
                    click=true;
                    break;
                case "string":
                    //输出到日志文件
                    say=arguments[i];
                    break;
                default:
                    //参数错误
                    break
            }
        }
    }
    do {
        let times=time();
        let bitmap = JcScreen();
        let result = image.cmpMultiColor(bitmap,str,sim,0,0,0,0);
        image.recycle(bitmap);
        if(result>=0){
            if(click){
                if(!tb){
                    let temp=parseColor(str[result]);
                    tb=[temp[0][0],temp[0][1]];
                }
                clickPoint(tb[0],tb[1])
            }
            if(say){
                //输出到日志文件
                logi(say)
            }
            if(delay>0){
                sleep(delay)
            }
            return result;
        }else if(waiting>0){
            //继续等待
            sleep(350);
            waiting-=time()-times;
        }
    }while (waiting>0);
    return -1
}
/**
 * @return {null|AutoImage}
 */
function JcScreen() {
    for (let i = 0; i < 3; i++) {
        let pic=image.captureFullScreenEx();
        if(pic){
            return pic
        }
        logi('截图失败尝试重启服务');
        let temp=CheckEnv();
        if(!temp){
            break;
        }
    }
    return null;
}
/**
 * @param a 找到的点
 * @param b 需要匹配的点
 * @param sim 精度
 * @param offset 偏差
 * @description  color对比
 * */
function colorSim(a,b,sim,offset) {
    let de=[0,0,0];
    offset=offset||'';
    if(offset!==''){
        de=getRbgFromHex(offset)
    }
    a=getRgbFromInt(a);
    b=getRgbFromInt(b);
    //logd([a,b,de]);
    for (let i = 0; i <=2 ; i++) {
        if(colorCompare(a[i],b[i],de[i],sim)===false){
            return false
        }else {
            //logd(i+'符合');
        }
    }
    return true
}
function colorCompare(a,b,c,sim) {
    let max=b+c+(255-sim*255);
    max=max>255?255:max;
    let min=b-c-(255-sim*255);
    min=min<0?0:min;
    return a>=min&&a<=max;
}
/***************************节点系列************************/
/**
 * @description 津彩插件点击
 * <Br/>other int大于0正整数:超时时间毫秒
 * <Br/>int负整数:点击后延时
 * <Br/>string:点击后执行logi(),string:id,desc,则搜索的是id,desc;fix是text和desc同时搜索,加上Match则用上正则
 * <Br/>传入数组:则点击数组的坐标
 * <Br/>所有参数不区分顺序
 * <Br/>如传入布尔值true,则搜节点期间不会锁定节点
 * @return boolean|布尔型
 * @param str 默认是text搜索
 */
JcClick = function (str) {
    let set = {
        'waitTime': 0,
        'delay': 0,
        'say': '',
        'type': 'text',
        'tap': false,
        'fixMatch':false,
        'fix':false
    };
    let selectors ;
    if(arguments.length>=1){
        for (let v=1;v<arguments.length;v++) {
            switch (typeof (arguments[v])) {
                case "boolean":
                    set['fixMatch']=arguments[v];
                    break;
                case "object":
                    try {
                        if (typeof (arguments[v][0]) == 'number' && typeof (arguments[v][1]) == 'number') {
                            set['tap'] = [arguments[v][0], arguments[v][1]];
                        }
                    } catch (e) {
                        logd(e);
                    }
                    break;
                case "number":
                    if (arguments[v] < 0) {
                        set['delay'] = Math.abs(parseInt(arguments[v]));
                    } else {
                        set['waitTime'] = arguments[v];
                    }
                    break;
                case "string":
                    switch (arguments[v]) {
                        case 'id':
                            set['type'] = 'id';
                            break;
                        case 'idMatch':
                            set['type'] = 'idMatch';
                            break;
                        case 'textMatch':
                            set['type'] = 'textMatch';
                            break;
                        case 'desc':
                            set['type'] = 'desc';
                            break;
                        case 'descMatch':
                            set['type'] = 'descMatch';
                            break;
                        case 'fix':
                            set.fix=true;
                            break;
                        case 'fixMatch':
                            set.fixMatch=true;
                            break;
                        default:
                            set['say'] = arguments[v];
                            break;
                    }
                    break;
                default:
                    loge('JcClick包含错误参数');
                    break;
            }
        }
    }
    let node;
    if(set.fixMatch||set.fix){
        let over=time()+set.waitTime/1000;
        do {
            lockNode();
            if(set.fixMatch){
                node=textMatch(str).getOneNodeInfo(0);
                if(!node){
                    node=descMatch(str).getOneNodeInfo(0);
                }
            }else {
                node=text(str).getOneNodeInfo(0);
                if(!node){
                    node=desc(str).getOneNodeInfo(0);
                }
            }
            releaseNode();
            if(node){
                break;
            }
            if(set.waitTime>0){
                sleep(200)
            }
        }while (over>time());
    }else {
        switch (set.type) {
            case "id":
                selectors =id(str);
                break;
            case "desc":
                selectors = desc(str);
                break;
            case "idMatch":
                selectors =idMatch(str);
                break;
            case "textMatch":
                selectors =textMatch(str);
                break;
            case "descMatch":
                selectors =descMatch(str);
                break;
            default:
                selectors = text(str);
                break;
        }
        node =selectors.getOneNodeInfo(set.waitTime);
    }
    if(node){
        if(set['say']){
            logi(set['say'])
        }
        if (set['tap']) {
            clickPoint(set['tap'][0],set['tap'][1]);
            if(set['delay']){
                sleep(set['delay'])
            }
        }else {
            JcRandClick(node,set.delay);
        }
        return true
    }
    return false
};
/**
 * @description 津彩节点搜索插件text和desc同时搜索
 * <Br/>other int:超时时间毫秒
 * <Br/>string:非空字符串,或者非fix则使用正则
 * <Br/>boolean:false当前未锁定 ，将自动锁点;true表示已经锁了的节点,fix则搜节点期间不会再次锁定节点和解锁节点
 * <Br/>从第2个参数开始,不区分顺序
 * @param str string 待搜索文字,默认是fix搜索
 *@return {NodeInfo} 对象或者null
 */
function JcNode(str) {
    let delay=0;
    let type='fix';
    let lock=false;
    if(arguments.length>=1){
        for (let v=1;v<arguments.length;v++) {
            switch (typeof (arguments[v])) {
                case "boolean":
                    lock=arguments[v]/1000;
                    break;
                case "number":
                    delay=arguments[v];
                    break;
                case "string":
                    type=arguments[v]==='fix'?'fix':'fixMatch';
                    break;
                default:
                    loge('JcNode包含错误参数');
                    break;
            }
        }
    }
    let node;
    let timeOver=time()+delay/1000;
    do {
        if(!lock){
            lockNode();
        }
        if(type==='fixMatch'){
            node=textMatch(str).getOneNodeInfo(0);
        }else {
            node=text(str).getOneNodeInfo(0);
        }
        if(!node){
            if(type==='fixMatch'){
                node=descMatch(str).getOneNodeInfo(0);
            }else {
                node=desc(str).getOneNodeInfo(0);
            }
        }
        if(!lock){
            releaseNode();
        }
        if(node){
            break;
        }
        if(delay>0){
            sleep(500);
        }
    }while (timeOver>time());
    return node;
}
/**
 * @description 等待节点消失
 * @param str 节点标识
 * @param waitTime 超时时长(单位:秒)
 * @param type id,desc,text等
 * @return {boolean}
 */
function waitNodeDisappear(str,waitTime,type) {
    //等节点消失
    waitTime=waitTime||0;
    type=type||'text';
    let selectors,temp,fix=0;
    switch (type) {
        case "id":
            selectors =id(str);
            break;
        case "desc":
            selectors = desc(str);
            break;
        case "idMatch":
            selectors =idMatch(str);
            break;
        case "textMatch":
            selectors =textMatch(str);
            break;
        case "descMatch":
            selectors =descMatch(str);
            break;
        case "fix":
            fix=1;
            break;
        case "fixMatch":
            fix=2;
            break;
        default:
            selectors = text(str);
            break;
    }
    let overTime=time()+waitTime;
    do {
        if(fix>0){
            temp=JcNode('str',fix===1?'fix':'fixMatch');
        }else {
            temp=has(selectors);
        }
        if(temp){
            sleep(500);
        }else {
            return true
        }
    }while (time()<overTime);
    return false
}
function reLockNode() {
    releaseNode();sleep(200);lockNode();
}
function getCenter(data) {
    let ret=[];
    //data=JSON.parse(data);
    if(data.top){
        ret[0]=parseInt((data.right+data.left)/2);
        ret[1]=parseInt((data.bottom+data.top)/2);
    }
    return ret
}
/**
 * @description 拟人节点点击
 * @param data 节点或节点的范围
 * @param delay 第1次点击后延时[可缺省]
 * @param num 第2次点击后延时[可缺省]
 * @return {boolean}
 */
function JcRandClick(data,delay,num) {
    if(!data){
        return false;
    }
    num=num||0;
    if(typeof (data)==='object'){
        if(data.bounds){
            data=data.bounds;
        }
    }
    delay=delay||0;
    //data=JSON.parse(data);
    let x=JcRnd((data.right-data.left)*0.4+data.left,(data.right-data.left)*0.6+data.left);
    let y=JcRnd((data.bottom-data.top)*0.4+data.top,(data.bottom-data.top)*0.6+data.top);
    let times=num>0?2:1;
    let temp=false;
    for (let i = 0; i < times; i++) {
        temp=clickPoint(x,y);
        if(!temp){
            temp=AdbClick([x,y],delay);
        }
        if(delay&&i===0){
            sleep(delay);
        }else if (i===1&&num>0) {
            sleep(num)
        }
    }
    return temp;
}
/***************************数据库系列************************/
 /**
  *  @return {boolean}
 */
function SQLCreate(Db,tableName,sql,close) {
    close =close||false;
    if(close===false){
        sqlite.connectOrCreateDb(Db);
    }
    let createTable=false;
    try {
        createTable=sqlite.execSql("CREATE TABLE "+ tableName+"("+sql+');');
    }catch (e) {
        logd(false)
    }
    if(close===false){
        sqlite.close();
    }
    return createTable
}
/**
 * @return {boolean}
 */
function SQLAddField(Db,tableName,sql,close) {
    close =close||false;
    if(close===false){
        sqlite.connectOrCreateDb(Db);
    }
    let result=false;
    try {
        result = sqlite.execSql("ALTER TABLE "+ tableName+' ADD '+sql);sleep(30);
    }catch (e) {
        logd(false)
    }
    if(close===false){
        sqlite.close();
    }
    sleep(20);
    return result
}
/**
 * @return {null,object};
 */
function SQLSelect(Db, tableName, column, where, close) {
    close =close||false;
    column = column||'*';
    if(close===false){
        try {
            sqlite.connectOrCreateDb(Db);
        }catch (e) {
            logw('查询数据库时连接出错');
            sqlite.close();
            return null
        }
    }
    let sql="SELECT "+column+" FROM "+tableName;
    if(where){
        sql=sql+' WHERE '+where;
    }
    let result=null;
    try {
        result = sqlite.query(sql);sleep(30);
    }catch (e) {
        logd('查询数据库时读取数据错误');
        return null
    }
    if(close===false){
        sqlite.close();
    }
    sleep(30);
    if(result){
        if(typeof(result)==='object'){
            if(result.length===0){
                return null
            }
        }
    }
    return result
}
/**
 * @return {boolean}
 */
function SQLInsert(Db,tableName,data,close) {
    close =close||false;
    if(close===false){
        sqlite.connectOrCreateDb(Db);
    }
    let insert=false;
    try {
        insert = sqlite.insert(tableName,data);sleep(35);
    }catch (e) {
        logd(false)
    }
    if(close===false){
        sqlite.close();
    }
    sleep(15);
    return insert
}
/**
 * @return {boolean}
 */
function SQLUpdate(Db,tableName,map,where,close) {
    close =close||false;
    where=where||'';
    if(close===false){
        let create=false;
        try{
            create = sqlite.connectOrCreateDb(Db);
        }catch (e) {
            logw('SQLUpdate时连接数据库失败')
        }
        if(!create){
            sqlite.close();sleep(50);
            return false;
        }
    }
    let update = sqlite.update(tableName,map,where);
    if(close===false){
        sqlite.close();
    }
    sleep(50);
    return update;
}
/**
 * @return {boolean}
 */
function SQLDelete(Db,tableName,where,close) {
    close =close||false;
    where=where||'';
    if(close===false){
        sqlite.connectOrCreateDb(Db);
    }
    let result =false;
    let sql="DELETE FROM "+tableName;
    if(where){
        sql=sql+' WHERE '+where;
    }
    try {
        result  = sqlite.delete(sql);sleep(40);
    }catch (e) {
        logd(false)
    }
    if(close===false){
        sqlite.close();
    }
    sleep(50);
    return result
}
/***************************系统工具***************************/
function CheckEnv() {
    let temp=isServiceOk();
    if(!temp){
        let result = startEnv();
        logi('重启为'+result);
        sleep(500);
        if(result){
            temp=isServiceOk();
        }
    }
    return temp;
}
function LogChang() {
    shell.execCommand("cp /sdcard/logger/logs_0.csv /sdcard/logger/nb/."+time()+"csv");
    file.deleteAllFile('/sdcard/logger/logs_0.csv')
}
function RefreshPicture(pic) {
    shell.execCommand("am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file://"+pic);
    shell.execCommand("am broadcast -a android.intent.action.MEDIA_MOUNTED -d file://"+pic);
}
/**
 * @return {number}
 */
function JcRnd(min,max){
    return Math.floor(Math.random() * (max - min + 1) + min);
}
function getAndroidVerFloat() {
    let temp=device.getOSVersion();
    temp=temp.split('.');
    return parseFloat(temp[0]+'.'+temp[1]+temp[2]);
}
/**
 * @return {boolean}
 */
function HasNavigationBar() {
    let temp = shell.execCommand("dumpsys window windows");
    if(!temp){
        return true;
    }
    let ret=temp.indexOf('name=NavigationBar');
    if(ret>-1){
        //此处点击隐藏虚拟按钮处
        AdbClick(GXY.closeNavigationBar);
    }
    return ret > -1;
}
function AdbClick(tb,delay) {
    delay=delay||0;
    let x=tb[0]+utils.getRangeInt(-10,11);
    let y=tb[1]+utils.getRangeInt(-10,11);
    shell.execCommand("input tap "+x+' '+y);
    if(delay>0){
        sleep(delay)
    }
}
function JcLongClick(tx,ty,times){
    agentEvent.touchDown(tx,ty);
    sleep(times);
    agentEvent.touchUp(tx,ty);
}
/***************************应用系列***************************/
function JcPkg() {
    let temp=shell.execAgentCommand('dumpsys activity | grep "Focus"');
    if(typeof temp==='string'){
        let res=temp.match(/\s([^/\s]+)\//);
        if(res){
            if(typeof res==='object'){
                return res[res.length-1];
            }
        }
    }
    return null
}
/***************************时间日期***************************/
function today(num) {
    let date;
    if(num){
        date =new Date(num)
    }else {
        date =new Date();
    }
    let mon=date.getMonth()+1;
    let day=date.getDate();
    let M=doHandleMonth(mon);
    let D=doHandleMonth(day);
    return parseInt(date.getFullYear()+''+M+''+D)
}
function toDay(type) {
    type=type||'-';
    let now = new Date();
    let nowYear = now.getFullYear();
    let nowMonth = now.getMonth();
    let nowDate = now.getDate();
    nowMonth = doHandleMonth(nowMonth + 1);
    nowDate = doHandleMonth(nowDate);
    return nowYear+type+nowMonth+type+nowDate
}
function doHandleMonth(month){
    if(month.toString().length===1){
        month = "0" + month;
    }
    return month;
}
/**
 * @description 获取今天是今年的第几周
 * */
function getWeek(){
    let date=new Date();
    let date2=new Date(date.getFullYear(), 0, 1);
    let day1=date.getDay();
    if(day1===0) day1=7;
    let day2=date2.getDay();
    if(day2===0) day2=7;
    let d = Math.round((date.getTime() - date2.getTime()+(day2-day1)*(24*60*60*1000)) / 86400000);
    return Math.ceil(d /7)+1;
}
function time(){return Math.floor((new Date).getTime()/1e3)}
/**
 * @description 获取时分组成的数值,如2100是21点,830是8点30分
 * @return {number}
 */
function timeInt() {
    let temp=new Date();
    let ret=temp.getMinutes();
    if(ret<10){
        ret=temp.getHours()+'0'+ret;
    }else {
        ret=temp.getHours()+''+ret;
    }
    return parseInt(ret)
}
/***************************其它系列***************************/
function dump(arr) {
    for (let key in arr) {
        if (typeof (arr[key]) == 'array' || typeof (arr[key]) === 'object') {//递归调用
            logd(key + '[');
            dump(arr[key]);
            logd(']')
        } else {
            logd(key + ' = ' + arr[key]);
        }
    }
}
function printJson(data){
    logd(JSON.stringify(data));
}
function isJsonString(str) {
    if(typeof (str)!=='string'){
        return false
    }
    if (/\{/.test(str)) {
        try {
            JSON.parse(str);
            return true
        } catch (err) {
            return false
        }
    }
    return false
}
/**
 * @return {boolean}
 */
function JcClickArr(Arr) {
    try{
        return clickPoint(Arr[0],Arr[1])
    }catch (e) {
        return false
    }
}
/**
 * @return {boolean}
 * @description 检测是否已经上锁了,自动执行上锁,返回解锁前的状态
 */
function UnLock() {
    let ret=false;
    let result = shell.execAgentCommand("dumpsys window policy|grep mShowingLockscreen");
    if(result){
        if(result.indexOf('mShowingLockscreen=true')>-1){
            logi('需要解锁屏幕');
            ret=true;
            shell.execAgentCommand("input keyevent 26");
            sleep(1200);
            if(phoneInfo.height===1280){
                swipeToPoint(500,700,500,50,400);
            }else {
                swipeToPoint(500,1000,500,80,400);
            }
        }else {
            logi('不需要解锁')
        }
    }
    return ret;
}
function DoubleClick(num) {
    num=num||12;
    let w=device.getScreenWidth()/2,h=device.getScreenHeight()/2;
    let x=[
        JcRnd(w-num,w+num),
        JcRnd(h-num,h+num),
        JcRnd(w-num,w+num),
        JcRnd(h-num,h+num),
    ];
    clickPoint(x[0],x[1]);
    sleep(180);
    clickPoint(x[0],x[1]);
}